package com.example.jrfwcwgl.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.client.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.jrfwcwgl.entity.*;
import com.example.jrfwcwgl.enums.BalanceTypeEnum;
import com.example.jrfwcwgl.enums.ClearingConfirmStateEnum;
import com.example.jrfwcwgl.enums.DzStateEnum;
import com.example.jrfwcwgl.enums.OperationTypeEnum;
import com.example.jrfwcwgl.mapper.TCwClearingMapper;
import com.example.jrfwcwgl.service.*;
import com.example.jrfwcwgl.utils.BigdecimalUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.org.dto.TCwClearingDto;
import com.org.vo.ResultEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 结算表 服务实现类
 * </p>
 *
 * @author 龚梦
 * @since 2021-04-08
 */
@Service
@Slf4j
public class TCwClearingServiceImpl extends ServiceImpl<TCwClearingMapper, TCwClearing> implements ITCwClearingService {
    @Autowired
    private TCwClearingMapper cwClearingMapper;
    /**
     * 支付订单
     */
    @Autowired
    private ITCwPayOrderService cwPayOrderService;
    /**
     * 支付订单明细
     */
    @Autowired
    private ITCwPayOrderDetailService cwPayOrderDetailService;
    /**
     * 商户账号
     */
    @Autowired
    private ITMCompanyAccountService companyAccountService;
    /**
     * 充值提现申请
     */
    @Autowired
    private ITCwCztxApplyService cwCztxApplyService;
    /**
     * 企业账户明细
     */
    @Autowired
    private ITCwBalanceService cwBalanceService;

    /**
     * @param @param  settlementManagementRequestDto
     * @param @return 参数
     * @Description：结算管理
     * @return返回值说明
     */
    @Override
    public PageInfo<TCwClearing> selectTCwClearing(TCwClearingDto tCwClearingDto) {
        log.info("settlementManagement处理 Start...");
        PageHelper.startPage(tCwClearingDto.getPageNum(), tCwClearingDto.getPageSize());
        List<TCwClearing> settlementManagement = cwClearingMapper.settlementManagement(tCwClearingDto);
        log.info("settlementManagement处理 End...");
        return new PageInfo<TCwClearing>(settlementManagement);
    }


    /*
     * 确认结算Service处理 (结算确认以后，商户账户入账)
     * @param confirmClearingRequestDto
     */
    @Override
    public ResultEntity confirmClearing(TCwClearingDto tCwClearingDto) {

        log.info("confirmClearing确认结算处理 Start...");

        if (tCwClearingDto == null
                || tCwClearingDto.getClearingIdList() == null
                || tCwClearingDto.getClearingIdList().size() == 0) {

            log.warn("----结算对象数据无。");
            return ResultEntity.error("结算对象数据无");
        }

        // 取得需要结算的记录ID
        List<Long> clearingIdList = tCwClearingDto.getClearingIdList();

        log.warn("----结算对象数据共{}条。", clearingIdList.size());

        // 循环处理每一个结算记录
        for (Long clearingItemId : clearingIdList) {

            log.info("--------当前处理结算ID：{}", clearingItemId);

            // 1、************ 获取对应结算记录
            TCwClearing clearing = cwClearingMapper.selectById(clearingItemId);

            if (clearing == null || StringUtils.isBlank(clearing.getPayOrderNo())) {
                log.warn("--------结算记录查询无。");
                continue;
            }

            // 2、************ 根据结算记录中的支付订单号查询对应的支付订单明细，
            //    并且进行业务订单金额的商户入账更新操作
            TCwPayOrderDetail queryOption = new TCwPayOrderDetail();
            // 支付订单No
            queryOption.setPayOrderNo(clearing.getPayOrderNo());
            queryOption.setDelFlg(false);
            QueryWrapper<TCwPayOrderDetail> queryOptionWrap = new QueryWrapper<TCwPayOrderDetail>(queryOption);
            List<TCwPayOrderDetail> orderDetailList = cwPayOrderDetailService.list(queryOptionWrap);

            if (orderDetailList == null || orderDetailList.size() == 0) {
                log.warn("--------该结算记录对应的支付订单流水明细查询无。");
                continue;
            }

            for (TCwPayOrderDetail orderDetail : orderDetailList) {

                // add by fl 20180524 增加金融服务的场景 start
                if (orderDetail.getCanClearingAmount() == null
                        || BigdecimalUtils.isEqualInTwoBigdecimal(orderDetail.getCanClearingAmount(), BigDecimal.ZERO)) {
                    // 商户可结算金额为空或者=0的时候，无需结算
                    log.debug("--------该明细无商户可结算金额，无需结算，处理跳过。");
                    continue;
                }
                // add by fl 20180524 增加金融服务的场景 end

                // 2-1、企业账户更新（结算入账处理，包括企业账户流水的结算状态更新）
                this.updateBalanceInConfirmClearing(orderDetail);
                log.debug("--------企业账户及账户流水明细更新完成。");
                // 2-2、更新对应的业务订单状态(充值提现申请表和收款计划表)
                this.updateBusinessOrderInConfirmClearing(orderDetail);
                log.debug("--------业务订单状态更新完成。");

            }

            // 3、************ 更新对应的支付订单信息状态为已结算
            this.updatePayOrderInConfirmClearing(orderDetailList.get(0).getPayOrderId());

            log.debug("--------支付订单结算状态更新完成。");

            // 4、************ 更新选中的结算记录的结算状态(从未确认更改为已确认)
            TCwClearing clearingForUpdate = new TCwClearing();
            clearingForUpdate.setId(clearingItemId);
            // 结算确认状态（2：已确认）
            clearingForUpdate.setClearingConfirmState(ClearingConfirmStateEnum.YQR.getIndex());
            // 结算确认人
            clearingForUpdate.setClearingConfirmUserId(tCwClearingDto.getClearingConfirmUserId());
            // 结算确认时间
            clearingForUpdate.setClearingConfirmDate(new Date());

            clearingForUpdate.setUpdateUserid(tCwClearingDto.getUpdateUserid());
            clearingForUpdate.setUpdateTime(new Date());

            // 更新结算表
            this.updateById(clearingForUpdate);

            log.debug("--------结算表更新完成。");

        }

        log.info("confirmClearing确认结算处理 End.");
        return ResultEntity.ok("结算表更新完成");
    }

    /**
     * 结算确认的时候，更新对应的支付订单信息状态为已结算
     *
     * @param payOrderId
     */
    private void updatePayOrderInConfirmClearing(Long payOrderId) {

        log.info("updatePayOrderInConfirmClearing结算确认的时候，更新对应的支付订单信息状态为已结算处理 Start...");

        TCwPayOrder updateEntity = new TCwPayOrder();
        updateEntity.setId(payOrderId);
        // 对账状态：已结算
        updateEntity.setDzState(DzStateEnum.YJS.getIndex());

        //updateEntity.setUpdateUserid(this.getBusinessLoginUserId());
        updateEntity.setUpdateTime(new Date());

        // 更新支付订单表
        this.cwPayOrderService.updateById(updateEntity);

        log.info("updatePayOrderInConfirmClearing结算确认的时候，更新对应的支付订单信息状态为已结算处理 End.");
    }

    /**
     * 结算确认的时候，企业账户更新（结算入账处理）
     *
     * @param orderDetail
     */
    private void updateBusinessOrderInConfirmClearing(TCwPayOrderDetail orderDetail) {

        log.info("updateBalanceInConfirmClearing结算确认的时候，企业账户更新处理 Start...");

        // 目前业务中，入金的业务包括企业充值和企业收款即租客支付费用（金融相关业务的结算在前面已经过滤了一遍，都这里的理论上都是需要结算的费用）
        log.info("----请求参数：{}", JSON.toJSONString(orderDetail));

        if (OperationTypeEnum.CZ.getIndex() == orderDetail.getBusinessOrderType()
                || OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {

            // 入账金额
            BigDecimal confirmAmount = orderDetail.getBusinessOrderAmount();

            // 1、恢复企业的可提现余额，减少对应的冻结金额
            // 1-1、查询商户账号信息
            TMCompanyAccount companyAccountOption = new TMCompanyAccount();
            companyAccountOption.setBusinessId(orderDetail.getBusinessId());
            companyAccountOption.setDelFlg(false);
            QueryWrapper<TMCompanyAccount> queryWrap = new QueryWrapper<TMCompanyAccount>(companyAccountOption);

            TMCompanyAccount companyAccount = companyAccountService.getOne(queryWrap);

            if (companyAccount == null) {
                log.error("----当前商户的企业账户信息查询不存在，商户账户更新跳过。商户ID：{}", orderDetail.getBusinessId());
                return;
            }

            // 1-2、更新商户账户余额
            TMCompanyAccount companyAccountForUpdate = new TMCompanyAccount();
            companyAccountForUpdate.setId(companyAccount.getId());
            // 可用余额
            companyAccountForUpdate.setCashableAmount(this.amountSum(companyAccount.getCashableAmount(), confirmAmount));
            // 冻结余额（不可使用余额）
            companyAccountForUpdate.setFrozenAmount(this.amountSub(companyAccount.getFrozenAmount(), confirmAmount));

            companyAccountForUpdate.setUpdateUserid(companyAccount.getUpdateUserid());
            companyAccountForUpdate.setUpdateTime(new Date());

            // 更新商户账户余额信息
            this.companyAccountService.updateById(companyAccountForUpdate);

            log.info("----更新商户账户余额完成，更新数据({}).", JSON.toJSONString(companyAccountForUpdate));

            // 2、更新该笔企业账户流水对应的结算状态(balance表)
            if (OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {
                // 目前充值只有成功未成功的状态，没有管理结算状态。  租客交费有结算状态，故业务收款的时候，需要更新账户流水状态

                // 2-1、查询对应的账户明细流水记录
                // 查询商户账号信息
                TCwBalance cwBalanceOption = new TCwBalance();
                // 商户ID
                cwBalanceOption.setBusinessId(orderDetail.getBusinessId());
                // 收支类型：收入
                cwBalanceOption.setBalanceType(BalanceTypeEnum.SR.getIndex());
                // 操作类型：收款
                cwBalanceOption.setOperationType(OperationTypeEnum.SK.getIndex());
                // 业务订单ID
                cwBalanceOption.setYwOrderId(orderDetail.getBusinessOrderPlanId());
                cwBalanceOption.setDelFlg(false);
                QueryWrapper<TCwBalance> queryBalanceWrap = new QueryWrapper<TCwBalance>(cwBalanceOption);

                TCwBalance balanceEntity = cwBalanceService.getOne(queryBalanceWrap);

                if (balanceEntity == null) {
                    log.error("----当前结算审核数据对应的企业账户Balance明细信息查询不存在，商户账户明细更新跳过。查询条件：{}", JSON.toJSONString(cwBalanceOption));
                    return;
                }

                // 2-2、企业账户明细更新
                TCwBalance cwBalanceForUpdate = new TCwBalance();
                cwBalanceForUpdate.setId(balanceEntity.getId());
                cwBalanceForUpdate.setStatusCode(DzStateEnum.YJS.getIndex());  // 已结算
                cwBalanceForUpdate.setStatusName(DzStateEnum.YJS.getName());

                //cwBalanceForUpdate.setUpdateUserid(this.getLoginUserid());
                cwBalanceForUpdate.setUpdateTime(new Date());

                this.cwBalanceService.updateById(cwBalanceForUpdate);

                log.info("----更新企业账户Balance明细完成，更新数据({}).", JSON.toJSONString(cwBalanceForUpdate));
            }

        }

        log.info("updateBalanceInConfirmClearing结算确认的时候，企业账户更新处理 End.");
    }

    /**
     * 结算确认的时候，企业账户更新（结算入账处理）
     *
     * @param orderDetail
     */
    private void updateBalanceInConfirmClearing(TCwPayOrderDetail orderDetail) {

        log.info("updateBalanceInConfirmClearing结算确认的时候，企业账户更新处理 Start...");

        // 目前业务中，入金的业务包括企业充值和企业收款即租客支付费用（金融相关业务的结算在前面已经过滤了一遍，都这里的理论上都是需要结算的费用）
        log.info("----请求参数：{}", JSON.toJSONString(orderDetail));

        if (OperationTypeEnum.CZ.getIndex() == orderDetail.getBusinessOrderType()
                || OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {

            // 入账金额
            BigDecimal confirmAmount = orderDetail.getBusinessOrderAmount();

            // 1、恢复企业的可提现余额，减少对应的冻结金额
            // 1-1、查询商户账号信息
            TMCompanyAccount companyAccountOption = new TMCompanyAccount();
            companyAccountOption.setBusinessId(orderDetail.getBusinessId());
            companyAccountOption.setDelFlg(false);
            QueryWrapper<TMCompanyAccount> queryWrap = new QueryWrapper<TMCompanyAccount>(companyAccountOption);

            TMCompanyAccount companyAccount = companyAccountService.getOne(queryWrap);

            if (companyAccount == null) {
                log.error("----当前商户的企业账户信息查询不存在，商户账户更新跳过。商户ID：{}", orderDetail.getBusinessId());
                return;
            }

            // 1-2、更新商户账户余额
            TMCompanyAccount companyAccountForUpdate = new TMCompanyAccount();
            companyAccountForUpdate.setId(companyAccount.getId());
            // 可用余额
            companyAccountForUpdate.setCashableAmount(this.amountSum(companyAccount.getCashableAmount(), confirmAmount));
            // 冻结余额（不可使用余额）
            companyAccountForUpdate.setFrozenAmount(this.amountSub(companyAccount.getFrozenAmount(), confirmAmount));

            //companyAccountForUpdate.setUpdateUserid(this.getBusinessLoginUserId());
            companyAccountForUpdate.setUpdateTime(new Date());

            // 更新商户账户余额信息
            this.companyAccountService.updateById(companyAccountForUpdate);

            log.info("----更新商户账户余额完成，更新数据({}).", JSON.toJSONString(companyAccountForUpdate));

            // 2、更新该笔企业账户流水对应的结算状态(balance表)
            if (OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {
                // 目前充值只有成功未成功的状态，没有管理结算状态。  租客交费有结算状态，故业务收款的时候，需要更新账户流水状态

                // 2-1、查询对应的账户明细流水记录
                // 查询商户账号信息
                TCwBalance cwBalanceOption = new TCwBalance();
                // 商户ID
                cwBalanceOption.setBusinessId(orderDetail.getBusinessId());
                // 收支类型：收入
                cwBalanceOption.setBalanceType(BalanceTypeEnum.SR.getIndex());
                // 操作类型：收款
                cwBalanceOption.setOperationType(OperationTypeEnum.SK.getIndex());
                // 业务订单ID
                cwBalanceOption.setYwOrderId(orderDetail.getBusinessOrderPlanId());
                cwBalanceOption.setDelFlg(false);
                QueryWrapper<TCwBalance> queryBalanceWrap = new QueryWrapper<TCwBalance>(cwBalanceOption);

                TCwBalance balanceEntity = this.cwBalanceService.getOne(queryBalanceWrap);

                if (balanceEntity == null) {
                    log.error("----当前结算审核数据对应的企业账户Balance明细信息查询不存在，商户账户明细更新跳过。查询条件：{}", JSON.toJSONString(cwBalanceOption));
                    return;
                }

                // 2-2、企业账户明细更新
                TCwBalance cwBalanceForUpdate = new TCwBalance();
                cwBalanceForUpdate.setId(balanceEntity.getId());
                cwBalanceForUpdate.setStatusCode(DzStateEnum.YJS.getIndex());  // 已结算
                cwBalanceForUpdate.setStatusName(DzStateEnum.YJS.getName());

                //cwBalanceForUpdate.setUpdateUserid(this.getLoginUserid());
                cwBalanceForUpdate.setUpdateTime(new Date());

                this.cwBalanceService.updateById(cwBalanceForUpdate);

                log.info("----更新企业账户Balance明细完成，更新数据({}).", JSON.toJSONString(cwBalanceForUpdate));
            }

        }

        log.info("updateBalanceInConfirmClearing结算确认的时候，企业账户更新处理 End.");

    }

    /**
     * 两个BigDecimal 求和
     *
     * @param //cashableAmount
     * @param //confirmAmount
     * @return
     */
    private BigDecimal amountSum(BigDecimal obj1, BigDecimal obj2) {
        if (obj1 == null && obj2 == null) {
            return BigDecimal.ZERO;
        }
        if (obj1 == null) {
            return obj2;
        } else if (obj2 == null) {
            return obj1;
        } else {
            return obj1.add(obj2);
        }
    }

    /**
     * 返回obj1 - obj2
     * 减完的结果>=0，小于0的时候，全部按0返回
     *
     * @param obj1
     * @param obj2
     * @return
     */
    private BigDecimal amountSub(BigDecimal obj1, BigDecimal obj2) {

        if (obj1 == null) {
            return BigDecimal.ZERO;
        }

        if (obj2 == null) {
            return obj1;
        } else {
            BigDecimal subResult = obj1.subtract(obj2);
            if (subResult.compareTo(BigDecimal.ZERO) < 0) {
                return BigDecimal.ZERO;
            } else {
                return subResult;
            }
        }
    }

}
